//-----------------------------------------------------------------------------------------------------//
//																	                                   //
// number_line.cpp  contains implementation	of the number_line										   //
//																									   //
// author	: Eng. Ahmed Yasser																		   //
// data		: 21-01-2015																			   //
//																	                                   //
//-----------------------------------------------------------------------------------------------------//
#include "..\include\number_line.h"


number_line_t create_number_line(float x, float y, float s, unsigned int l, bool is_v)
{
	number_line_t number_line;
	number_line.length = l;
	number_line.origin_x = x;
	number_line.origin_y = y;
	number_line.step = s;
	number_line.is_vertical = is_v;

	number_line.draw_info.sx = number_line.origin_x - number_line.step * number_line.length;
	number_line.draw_info.ex = number_line.origin_x + number_line.step * number_line.length;
	number_line.draw_info.length_x = number_line.draw_info.ex - number_line.draw_info.sx;

	return number_line;
}

void transform_to_number_line(const number_line_t& nl)
{
	// scale the model to display the number line
	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
	if (nl.is_vertical)
		glScaled(1.0, 1.0 / (nl.draw_info.length_x / 2.0), 1.0);		
	else
		glScaled(1.0 / (nl.draw_info.length_x / 2.0), 1.0, 1.0);
}

void draw_number_line(const number_line_t& nl, float r, float g, float b, float a)
{
	// transform to the number line
	transform_to_number_line(nl);

	float arrow_length = nl.draw_info.length_x / 100.0f;

	// draw the base line
	if (nl.is_vertical)
		draw_line(1.0f, nl.origin_x, nl.draw_info.sx, nl.origin_x, nl.draw_info.ex, r, g, b, a);
	else
		draw_line(1.0f, nl.draw_info.sx, nl.origin_y, nl.draw_info.ex, nl.origin_y, r, g, b, a);

	// draw the arrows
	if (nl.is_vertical)
	{
		draw_line(1.0f, nl.origin_x, nl.draw_info.ex, nl.origin_x - 0.02f, nl.draw_info.ex - arrow_length, r, g, b, a);
		draw_line(1.0f, nl.origin_x, nl.draw_info.ex, nl.origin_x + 0.02f, nl.draw_info.ex - arrow_length, r, g, b, a);
		draw_line(1.0f, nl.origin_x, nl.draw_info.sx, nl.origin_x - 0.02f, nl.draw_info.sx + arrow_length, r, g, b, a);
		draw_line(1.0f, nl.origin_x, nl.draw_info.sx, nl.origin_x + 0.02f, nl.draw_info.sx + arrow_length, r, g, b, a);
	}
	else
	{
		draw_line(1.0f, nl.draw_info.ex, nl.origin_y, nl.draw_info.ex - arrow_length, nl.origin_y - 0.02f, r, g, b, a);
		draw_line(1.0f, nl.draw_info.ex, nl.origin_y, nl.draw_info.ex - arrow_length, nl.origin_y + 0.02f, r, g, b, a);
		draw_line(1.0f, nl.draw_info.sx, nl.origin_y, nl.draw_info.sx + arrow_length, nl.origin_y - 0.02f, r, g, b, a);
		draw_line(1.0f, nl.draw_info.sx, nl.origin_y, nl.draw_info.sx + arrow_length, nl.origin_y + 0.02f, r, g, b, a);
	}

	// draw steps
	int s_length = -(int)nl.length + 1;
	int e_length = (int)nl.length - 1;
	for (int i = s_length; i <= e_length; i++)
	{
		float l_length = i == 0? 0.02f : 0.01f;

		if (nl.is_vertical)
			draw_line(1.0f, nl.origin_x - l_length, nl.origin_y + i * nl.step, 
					  nl.origin_x + l_length, nl.origin_y + i * nl.step, r, g, b, a);
		else
			draw_line(1.0f, nl.origin_x + i * nl.step, nl.origin_y - l_length, 
					  nl.origin_x + i * nl.step, nl.origin_y + l_length, r, g, b, a);

		float str_x = nl.is_vertical? nl.origin_x - 0.04f : nl.origin_x + i * nl.step - nl.draw_info.length_x / 150.0f;
		float str_y = nl.is_vertical? nl.origin_y + i * nl.step - nl.draw_info.length_x / 150.0f : nl.origin_y - 0.04f;
		
		char buffer[1024];
		sprintf_s(buffer, "%.1f", nl.origin_x + i * nl.step);
		draw_string(false, buffer, str_x, str_y, r, g, b, a);
	}
}

void draw_interval(const interval_t& interval, const number_line_t& nl, float r, float g, float b, float a)
{
	// transform to the number line
	transform_to_number_line(nl);

	// draw the open interval bracket
	if (nl.is_vertical)
	{
		if (interval.start_type == OPENED_INTERVAL)
			draw_string(true, "(", nl.origin_x - 0.01f, interval.start, r, g, b, a);
		else if (interval.start_type == CLOSED_INTERVAL)
			draw_string(true, "[", nl.origin_x - 0.01f, interval.start, r, g, b, a);
		if (interval.end_type == OPENED_INTERVAL)
			draw_string(true, ")", nl.origin_x - 0.01f, interval.end, r, g, b, a);
		else if (interval.end_type == CLOSED_INTERVAL)
			draw_string(true, "]", nl.origin_y - 0.01f, interval.end, r, g, b, a);
	}
	else
	{
		if (interval.start_type == OPENED_INTERVAL)
			draw_string(true, "(", interval.start, nl.origin_y - 0.01f, r, g, b, a);
		else if (interval.start_type == CLOSED_INTERVAL)
			draw_string(true, "[", interval.start, nl.origin_y - 0.01f, r, g, b, a);
		if (interval.end_type == OPENED_INTERVAL)
			draw_string(true, ")", interval.end, nl.origin_y - 0.01f, r, g, b, a);
		else if (interval.end_type == CLOSED_INTERVAL)
			draw_string(true, "]", interval.end, nl.origin_y - 0.01f, r, g, b, a);
	}	

	// compute the starting x and ending x
	float sx = 0.0f, ex = 0.0f;
	if (interval.start_type != INFINITE_INTERVAL)
		sx = interval.start;
	else
		sx = nl.is_vertical? nl.origin_y - nl.step * nl.length : nl.origin_x - nl.step * nl.length;

	if (interval.end_type != INFINITE_INTERVAL)
		ex = interval.end;
	else
		ex = nl.is_vertical? nl.origin_y + nl.step * nl.length : nl.origin_x + nl.step * nl.length;

	// draw the interval line
	if (nl.is_vertical)
		draw_line(3.0f, nl.origin_x + 0.01f, sx, nl.origin_x + 0.01f, ex, r, g, b, a);
	else
		draw_line(3.0f, sx, nl.origin_y + 0.01f, ex, nl.origin_y + 0.01f, r, g, b, a);
}

void draw_number(float num, const number_line_t& nl, float r, float g, float b, float a)
{
	// transform to the number line
	transform_to_number_line(nl);

	// draw the number
	if (nl.is_vertical)
		draw_point(nl.origin_x, num + nl.origin_y, r, g, b, a);
	else
		draw_point(num + nl.origin_x, nl.origin_y, r, g, b, a);

	// draw the number string
	char buffer[1024];
	sprintf_s(buffer, "%.1f", num);
	if (nl.is_vertical)
		draw_string(false, buffer, nl.origin_x - 0.04f, num + nl.origin_y, r, g, b, a);
	else
		draw_string(false, buffer, num + nl.origin_x, nl.origin_y - 0.04f, r, g, b, a);
}

void draw_numbers(std::vector<float> nums, const number_line_t& nl, float r, float g, float b, float a)
{
	for (unsigned int i = 0; i < nums.size(); i++)
		draw_number(nums[i], nl, r, g, b, a);
}